# -*- encoding: utf-8 -*-

# Filename:   main.py
# Created on: 2018-05-29 16:10:16
# Author:     wuxc (https://github.com/wuxc)

import sys
import socket
import struct

from api_pb2 import *

class PbApiClient(object):
    def __init__(self, addr):
        self.addr = addr
        self.sock = None
        self.buf = ''

    def _connect(self):
        if self.sock is not None:
            return
        self.buf = ''
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            self.sock.connect(self.addr)
            return
        except socket.error:
            self.sock = None

    def send(self, data):
        self._connect()
        if self.sock is None:
            print "[SEND ERR]: not connected"
            return False
        size = len(data)
        data = struct.pack("<i%ds" % size, size, data)
        try:
            self.sock.send(data)
            return True
        except socket.error, detail:
            print "[SEND ERR]:", ','.join([str(v) for v in detail])
            self.sock = None
            return False

    def recv(self):
        if self.sock is None:
            print "[RECV ERR]: not connected"
            return
        buf = []
        while True:
            try:
                data = self.sock.recv(4096)
            except socket.error, detail:
                print "[RECV ERR]:", ','.join([str(v) for v in detail])
                self.sock = None
                return
            buf.append(data)
            if len(data) < 4096: break

        self.buf += ''.join(buf)
        if len(self.buf) < 4 :
            print "[DATA ERROR] buf < 4"
            return
        size = struct.unpack('i', self.buf[:4])[0]
        if len(self.buf) < size+4:
            print "[DATA ERROR] buf not enough"
            return
        data, self.buf = self.buf[4:size+4], self.buf[size+4:]
        msg = ApiMessage.FromString(data)
        return msg

    # 获取机器人基础信息
    def queryRobots(self, *args):
        # send
        msg = ApiMessage()
        msg.type = MSG_REQ
        msg.req.type = Request.REQ_ROBOT_INFO
        for rid in args:
            msg.req.robot_ids.append(rid)
        if not self.send(msg.SerializeToString()):
            return
        # recv
        rmsg = self.recv()
        if rmsg is None:
            return
        print "queryRobots result:", rmsg.resp

    # 下达新任务, 返回任务id, 0表示失败
    def newMission(self, uuid, mapname, spots):
        # send 
        msg = ApiMessage()
        msg.type = MSG_REQ
        msg.req.type = Request.REQ_MISSION_NEW
        m = msg.req.mission
        m.ref_uuid = uuid
        m.src = "python"
        m.description = "my test mission"
        m.req_robot = 1
        m.priority = 3
        if not self.send(msg.SerializeToString()):
            return 0
        rmsg = self.recv()
        if rmsg is None or rmsg.resp is None:
            return 0
        if not rmsg.resp.ok:
            print "newMission not ok, reason: %s" % rmsg.resp.err_msg
            return 0
        print "newMission result", rmsg.resp
        return rmsg.resp.mission.id

    # 获取任务信息
    def queryMission(self, mid):
        # send
        msg = ApiMessage()
        msg.type = MSG_REQ
        msg.req.type = Request.REQ_MISSION_INFO
        msg.req.mission_id = mid
        if not self.send(msg.SerializeToString()):
            return
        # recv
        rmsg = self.recv()
        if rmsg is None:
            return
        print "queryMission by id result:", rmsg.resp


    # 获取任务完整信息
    def queryMissionByUuid(self, uuid):
        # send
        msg = ApiMessage()
        msg.type = MSG_REQ
        msg.req.type = Request.REQ_MISSION_INFO
        msg.req.mission_uuid = uuid
        if not self.send(msg.SerializeToString()):
            return
        # recv
        rmsg = self.recv()
        if rmsg is None:
            return
        print "queryMission by uuid result:", rmsg.resp

    # 取消任务
    def cancelMission(self, uuid):
        if not uuid:
            return
        # send
        msg = ApiMessage()
        msg.type = MSG_REQ
        msg.req.type = Request.REQ_MISSION_COMMAND_NEW
        msg.req.mscmd.src = "python"
        msg.req.mscmd.sync = True
        msg.req.mscmd.mission_uuid = uuid
        msg.req.mscmd.cmd = MissionCommand.MCMD_CANCEL
        if not self.send(msg.SerializeToString()):
            return
        # recv
        rmsg = self.recv()
        if rmsg is None:
            return
        print "cancelMission result:", rmsg.resp

if __name__ == '__main__':
    port = 8848
    if len(sys.argv) > 1:
        try:
            port = int(sys.argv[1])
        except:
            print "wrong port '%s', using default" % sys.argv[1]
            pass
    print "connect to server at", port
    addr = ("", port)
    client = PbApiClient(addr)
    client.queryRobots()
    client.queryRobots(1)
    mid = client.newMission("xxx-123", "test", (1,2,3))
    if mid != 0:
        client.queryMission(mid)
    client.cancelMission("xxx-123")
    client.queryMissionByUuid("xxx-123")

